﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using ArtMath.Component.Line;
using ArtMath.Attribute;
using ArtMath.Converter;
using ArtMath.Core.Data;
using ArtMath.Data;
using ArtMath.Component.Point;
using ArtMath.Core.Helper;
using ArtMath.Resource;
using ArtMath.PointCollection;
using ArtMath.CommonType;

namespace ArtMath.Component.Vector
{
    /// <summary>
    /// 垂直向量
    /// </summary>
    [Serializable]
    public class VerticalVector : VectorBase
    {
        StraightLineBase line;
        bool unlimit;
        PropertyDisplayer fpDisplayer;
        public VerticalVector(SketchPad pad, string name, StraightLineBase line, bool addToList = true) : base(pad, name, ToolTypeName.czxl, addToList)
        {
            AllowFix = false;
            StraightLine = line;
            FootPointDisplayer = new PropertyDisplayer(this, "FootPoint") { OffSet = AnchorOffset };
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("StraightLine"), TypeConverter(typeof(ExpandableObjectConverter))]
        public StraightLineBase StraightLine
        {
            get { return line; }
            set
            {
                line?.OutChildren_Line.Remove(this);
                line = value;
                line?.OutChildren_Line.Add(this);
            }
        }
        public override double NewSlope
        {
            get { return -1 / StraightLine.NewSlope; }
        }
        public override double NewPSlope
        {
            get { return Pad.GetVerticalLinePSlope(StraightLine.NewPSlope); }
        }
        public override bool PointsHaveConstraint
        {
            get { return true; }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("FootPoint"), TypeConverter(typeof(IntelliPointConverter))]
        public PointD FootPoint
        {
            get { return Point1.ToPointD().GetProjectivePoint(StraightLine.Location, StraightLine.Slope); }
        }
        [Browsable(false)]
        public PointD PFootPoint
        {
            get { return Pad.XYToPxy(FootPoint); }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "FootPoint", "Displayer")]
        public PropertyDisplayer FootPointDisplayer
        {
            get { return fpDisplayer; }
            set { fpDisplayer = value; }
        }
        [Browsable(false)]
        public override AngleStringX RotateAngle
        {
            get
            {
                return base.RotateAngle;
            }

            set
            {
                base.RotateAngle = value;
            }
        }
        [Browsable(false)]
        public override RPointS RotateCenter
        {
            get
            {
                return base.RotateCenter;
            }

            set
            {
                base.RotateCenter = value;
            }
        }
        public override PointD AnchorPoint(PropertyDisplayer disp)
        {
            if (disp == FootPointDisplayer)
            {
                return PFootPoint;
            }
            return base.AnchorPoint(disp);
        }
        public override void RefreshPropertyDisplayersText()
        {
            FootPointDisplayer.RefreshText();
            base.RefreshPropertyDisplayersText();
        }
        public override void RefreshPropertyDisplayersLocation()
        {
            FootPointDisplayer.RefreshLocation();
            base.RefreshPropertyDisplayersLocation();
        }
        public override void PaintProperties(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible)
            {
                FootPointDisplayer.Paint(gra);
            }
            base.PaintProperties(gra);
        }
        protected override void PointMoving_AsOutChildrenLimit(PointBase movePoint)
        {
            int movcnt = CountMovablePoints();
            switch (movcnt)
            {
                case 0:
                    if (!StraightLine.NewSlope.AlmostEqual(StraightLine.Slope))
                    {
                        throw new PointMovingException(this, OfTranslator2(Resources.JoinLocalizedString("EndPoint", "CannotMove")));
                    }
                    break;
                case 1:
                case 2:
                    PointBase fix, move;
                    if (Point2.Movable)
                    {
                        move = Point2;
                        fix = Point1;
                    }
                    else
                    {
                        move = Point1;
                        fix = Point2;
                    }
                    double[] abc = fix.ToPointD().GetABC(NewSlope);
                    PointD[] pts = CurveIntersection.StraightLineArcIntersection(abc[0], abc[1], abc[2], fix.ToPointD(), fix.DistanceTo(move), 0, Core.Helper.Angle.RadRound);
                    if (pts != null)
                    {
                        unlimit = fix.TempMoveLock = true;
                        try
                        {
                            move.Move(Pad.XYToPxy(move.ToPointD().GetNearestPoint(pts)));
                        }
                        finally
                        {
                            unlimit = fix.TempMoveLock = false;
                        }
                    }
                    break;
            }
        }
        public override PropertyDisplayer[] PropertyDisplayersCheckNearBy(PointD Plocation)
        {
            List<PropertyDisplayer> res = new List<PropertyDisplayer>(base.PropertyDisplayersCheckNearBy(Plocation));
            if (FootPointDisplayer.InRegion(Plocation))
            {
                res.Add(FootPointDisplayer);
            }
            return res.ToArray();
        }
        public override PointCollectionBase[] GetInPointMovingRange(PointBase movePoint, Base sender = null)
        {
            switch (CountMovablePoints())
            {
                case 1:
                    if (unlimit) return Universal.GenerateInstanceArray();
                    return new PointCollectionBase[] { new StraightLine((movePoint == Point1 ? Point2 : Point1).NewXY, NewSlope) };
            }
            return base.GetInPointMovingRange(movePoint, sender);
        }
        public override void CreateComponents()
        {
            if (Point1 == null)
            {
                CreateComponents(Resources.Translate("StartPoint"));
            }
            else
            {
                CreateComponents(Resources.Translate("TerminalPoint"), new PointCollectionBase[] { new StraightLine(Point1.ToPointD(), -1 / StraightLine.Slope) });
            }
        }
        public override void ComponentBuilding(Base component)
        {
            if (Point1 == null)
            {
                ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}");
                return;
            }
            SpareCoordinate = SpareCoordinate.GetProjectivePoint(Point1.Pxy, Pad.GetVerticalLinePSlope(StraightLine.PSlope));
            base.ComponentBuilding(component);
        }
    }
}
